41장 타이머
41-1. 호출 스케줄링
함수를 즉시 호출하지 않고 일정 시간이 경과된 이후에 호출되도록 함수 호출을 예약하는 것을 호출 스케줄링(Call Scheduling)이라 한다.
자바스크립트는 이를 위해 타이머 함수 setTimeout, setInterval과 이를 제거하는 clearTimeout, clearInterval을 제공한다.
타이머 함수는 ECMAScript 사양에 정의된 빌트인 함수가 아니라, 브라우저 환경과 Node.js 환경에서 모두 제공하는 호스트 객체다.
41-2. 타이머 함수
1) setTimeout / clearTimeout
단 한 번 동작하는 타이머를 생성한다.
- 기능: 두 번째 인자로 전달받은 시간(ms)이 경과한 후 첫 번째 인자의 콜백 함수가 호출된다
- 제거:
setTimeout이 반환한 고유한 타이머 ID를clearTimeout의 인자로 전달하여 취소한다
// 1초(1000ms) 후 콜백 함수 호출
const timerId = setTimeout(() => console.log('Hi!'), 1000);
// 타이머 취소
clearTimeout(timerId);2) setInterval / clearInterval
타이머가 취소될 때까지 반복 동작하는 타이머를 생성한다.
- 기능: 두 번째 인자로 전달받은 시간이 경과할 때마다 콜백 함수를 반복 호출한다
- 제거:
setInterval이 반환한 타이머 ID를clearInterval에 전달한다
41-3. 자바스크립트 엔진과 비동기 처리
자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택(콜 스택)을 갖는 싱글 스레드(Single Thread) 방식으로 동작한다.
- 블로킹: 동시에 두 가지 태스크를 실행할 수 없으므로, 실행 중인 태스크가 종료될 때까지 다음 태스크는 중단된다
- 타이머의 비동기성: 하지만 타이머 함수는 콜백 함수의 호출을 지연시킬 뿐, 이후의 코드를 블로킹하지 않고 즉시 실행되는 비동기 처리(Asynchronous) 방식으로 동작한다
41-4. 디바운스와 스로틀링 (성능 최적화)
scroll, resize, input, mousemove와 같은 이벤트는 짧은 시간 간격으로 연속해서 발생합니다. 이러한 이벤트에 바인딩된 핸들러가 매번 호출되면 성능에 문제를 일으킬 수 있습니다. 디바운스와 스로틀은 이러한 과도한 이벤트 핸들러 호출을 방지하는 프로그래밍 기법입니다.

1) 디바운스 (Debounce)
디바운스는 짧은 시간 간격으로 이벤트가 연속해서 발생하면 이벤트 핸들러를 호출하지 않다가, 일정 시간이 경과한 이후에 이벤트 핸들러가 단 한 번만 호출되도록 합니다. 즉, 연속된 이벤트를 그룹화하여 마지막에 한 번만 처리하는 방식입니다.
- 작동 원리: 설정한 시간(
delay)보다 짧은 간격으로 이벤트가 발생하면 이전 타이머를 취소하고 새로운 타이머를 재설정합니다. 결국 마지막 이벤트가 발생하고delay만큼 시간이 지났을 때 콜백 함수가 호출됩니다. - 주요 사례:
- input 이벤트: 사용자가 입력을 마쳤을 때만 Ajax 요청을 보내는 자동완성 UI
- 버튼 중복 클릭 방지: 빠르게 여러 번 클릭해도 마지막 한 번만 실행
- resize 이벤트: 브라우저 창 크기 조절이 끝났을 때만 실행

2) 스로틀 (Throttle)
스로틀은 짧은 시간 간격으로 이벤트가 연속해서 발생하더라도 일정한 시간 간격으로 이벤트 핸들러가 최대 한 번만 호출되도록 합니다. 즉, 이벤트를 그룹화하여 일정 시간 단위로 호출 주기를 만드는 방식입니다.
- 작동 원리: 이벤트가 발생하면 타이머를 설정하고, 타이머가 만료되기 전까지 발생하는 이벤트는 모두 무시합니다. 타이머가 만료되면 다음 이벤트 발생 시 다시 타이머를 설정하며 콜백을 호출합니다.
- 주요 사례:
- scroll 이벤트: 사용자가 스크롤할 때 실시간 위치를 계산하거나 무한 스크롤 UI를 구현할 때 성능 저하 방지
- mousemove 이벤트: 마우스 이동에 따른 과도한 연산 방지

3) 디바운스 vs 스로틀 요약 비교
| 구분 | 디바운스 (Debounce) | 스로틀 (Throttle) |
|---|---|---|
| 핵심 개념 | 여러 번의 이벤트를 마지막 한 번으로 처리 | 이벤트를 일정한 시간 간격으로 나누어 처리 |
| 실행 시점 | 이벤트가 멈추고 일정 시간이 지난 뒤 | 이벤트가 진행 중이어도 주기적으로 실행 |
| 비유 | ”다 쳤어? 그럼 이제 보낼게” (타이핑) | “아무리 빨라도 0.5초마다 한 번씩만 해” (스크롤) |
참고: 실무에서는 직접 구현하기보다는
Underscore나Lodash라이브러리에서 제공하는debounce와throttle함수를 사용하는 것을 권장합니다.